//
//  vdShaderLib.m
//  Void Dead
//
//  Created by Sidney Just on 28.02.10.
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import "vdShaderLib.h"
#import "matrix.h"

@implementation vdShaderLib

- (void)bindAttributeLocations:(vdShader *)sender {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if(sender == defaultShader)
	{
		glBindAttribLocation(sender.shader, 0, "a_position"); // Bind the a_position attribute
		glBindAttribLocation(sender.shader, 1, "a_texCoord"); // Bind the a_texCoord attribute
	}
	
	if(sender == fixedColor)
	{
		glBindAttribLocation(sender.shader, 0, "a_position"); // Bind the a_position attribute
		glBindAttribLocation(sender.shader, 1, "a_texCoord"); // Bind the a_texCoord attribute
	}
#endif
}

- (void)getUniformLocations:(vdShader *)sender {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if(sender == defaultShader)
	{
		// Get Attribute locations
		def_positionLoc = glGetAttribLocation(sender.shader, "a_position");
        def_texCoordLoc = glGetAttribLocation(sender.shader, "a_texCoord");
        
		// Get Uniform locations
        def_samplerLoc	= glGetUniformLocation(sender.shader, "s_texture");
		def_matrix		= glGetUniformLocation(sender.shader, "modelViewProjectionMatrix");
		def_colorLoc	= glGetUniformLocation(sender.shader, "v_texColor");
	}
	
	if(sender == fixedColor)
	{
		// Get Attribute locations
		fxd_positionLoc = glGetAttribLocation(sender.shader, "a_position");
        fxd_texCoordLoc = glGetAttribLocation(sender.shader, "a_texCoord");
        
		// Get Uniform locations
        fxd_samplerLoc	= glGetUniformLocation(sender.shader, "s_texture");
		fxd_matrix		= glGetUniformLocation(sender.shader, "modelViewProjectionMatrix");
		fxd_colorLoc	= glGetUniformLocation(sender.shader, "v_texColor");
	}
#endif
}

- (void)runShader:(vdShader *)sender {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if(sender == defaultShader)
	{
		glUniformMatrix4fv(def_matrix, 1, GL_FALSE, sender.matrix); // Send the projection matrix to the shader
		
		// Texture
		glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, sender.texture.texture); // Bind the texture
        glUniform1i(def_samplerLoc, 0); // Send the texture to the texture sampler uniform
		
		// Vertices
		glVertexAttribPointer(def_positionLoc, sender.positionsPerVertex, GL_FLOAT, GL_FALSE, 0, sender.vertices); // Send the vertices to the shader
        glEnableVertexAttribArray(def_positionLoc);
		
		glVertexAttribPointer(def_texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, sender.texCoords); // Send the texture coordinates to the shader
        glEnableVertexAttribArray(def_texCoordLoc);
		
		// Color
		glUniform4f(def_colorLoc, sender.color->red, sender.color->green, sender.color->blue, sender.color->alpha);
	}
	
	if(sender == fixedColor)
	{
		glUniformMatrix4fv(fxd_matrix, 1, GL_FALSE, sender.matrix); // Send the projection matrix to the shader
		
		// Texture
		glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, sender.texture.texture); // Bind the texture
        glUniform1i(fxd_samplerLoc, 0); // Send the texture to the texture sampler uniform
		
		// Vertices
		glVertexAttribPointer(fxd_positionLoc, sender.positionsPerVertex, GL_FLOAT, GL_FALSE, 0, sender.vertices); // Send the vertices to the shader
        glEnableVertexAttribArray(fxd_positionLoc);
		
		glVertexAttribPointer(fxd_texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, sender.texCoords); // Send the texture coordinates to the shader
        glEnableVertexAttribArray(fxd_texCoordLoc);
		
		// Color
		glUniform4f(fxd_colorLoc, sender.color->red, sender.color->green, sender.color->blue, sender.color->alpha);
	}
#endif
}

- (vdShader *)getShader:(vdLibShader)shd {
	switch(shd) {
		case vdShaderDefault:
			return defaultShader;
			break;
			
		case vdShaderFixed:
			return fixedColor;
			break;
	}
	
	return NULL;
}

static vdShaderLib *_sharedLib = NULL;

+ (vdShaderLib *)sharedLib {
	if(!_sharedLib)
	{
		_sharedLib = [[vdShaderLib alloc] init];
	}
	
	return _sharedLib;
}

- (id)init {
	if(!_sharedLib)
	{
		if(self = [super init])
		{
			defaultShader = [[vdShader alloc] init];
			[defaultShader setDelegate:self];
			[defaultShader loadVertexShader:@"defaultShader.vsh" andFragmentShader:@"defaultShader.fsh" fromHDD:YES];
			
			fixedColor = [[vdShader alloc] init];
			[fixedColor setDelegate:self];
			[fixedColor loadVertexShader:@"fixedColor.vsh" andFragmentShader:@"fixedColor.fsh" fromHDD:YES];
		}
		
		_sharedLib = self;
		return self;
	}else {
		[self release];
	}

	return _sharedLib;
}

- (void)dealloc {
	[defaultShader release];
	[fixedColor release];
	
	if(self == _sharedLib)
		_sharedLib = NULL;
	
	[super dealloc];
}

@end
